//+---------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation, 2008
//
// File: 
//      WebServicesApiLogger.cs
//
// Contents: 
//      Reputation Web Services Logger - data feed for the Data Points Logging
//
// Created by: 
//      Andrew Lin (yunlin@microsoft.com) March 5 2008
//
//----------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.Xml;
using System.Xml.Serialization;
using System.Reflection;
   
namespace Microsoft.Reputation.Services
{
    public class LogListingRequest
    {
        [XmlAttribute]
        public uint Type;
        [XmlAttribute]
        public string Guid; //XmlSerializer does not cope with Nullables, hence using string here
        [XmlAttribute]
        public uint ReturnObjectType;
        [XmlElement]
        public LogFilter Filter;
        [XmlElement]
        public string LastStamp;

        public LogListingRequest(ListingRequest listingRequest)
        {
            if(listingRequest == null)
            {
                throw new ArgumentNullException("listingRequest");
            }
            this.Type = listingRequest.Type;
            this.ReturnObjectType = listingRequest.ReturnObjectType;

            if (listingRequest.Guid.HasValue)
            {
                this.Guid = XmlConvert.ToString(listingRequest.Guid.Value);
            }

            if (listingRequest.LastStamp.HasValue)
            {
                this.LastStamp = XmlConvert.ToString(listingRequest.LastStamp.Value);
            }

            if (listingRequest.Filter != null)
            {
                this.Filter = new LogFilter(listingRequest.Filter);
            }
        }

        private LogListingRequest()
        {
        }
    }

    public class LogFilter
    {
        [XmlArray]
        public DataType[] RequestedData;
        [XmlArray]
        public string[] RequestedMetadata;
        [XmlArray]
        public Int32[] RequestedCategory;
        [XmlAttribute]
        public string LastStamp;

        public LogFilter(Filter filter)
        {
            if (filter == null)
            {
                throw new ArgumentNullException("filter");
            }
            if (filter.LastStamp.HasValue)
            {
                this.LastStamp = XmlConvert.ToString(filter.LastStamp.Value);
            }

            if (filter.RequestedData != null)
            {
                this.RequestedData = new DataType[filter.RequestedData.Count];
                int i = 0;
                foreach (DataType dataType in filter.RequestedData)
                {
                    this.RequestedData[i++] = dataType;
                }
            }

            if (filter.RequestedMetadata != null)
            {
                this.RequestedMetadata = new string[filter.RequestedMetadata.Count];
                int i = 0;
                foreach (string s in filter.RequestedMetadata)
                {
                    this.RequestedMetadata[i++] = s;
                }
            }

            if (filter.RequestedCategory != null)
            {
                this.RequestedCategory = new Int32[filter.RequestedCategory.Count];
                int i = 0;
                foreach (Int32 rc in filter.RequestedCategory)
                {
                    this.RequestedCategory[i++] = rc;
                }
            }
        }

        private LogFilter()
        {
        }
    }

    public class LogLookupRequestResponse
    {
        [XmlAttribute]
        public uint Type;
        [XmlAttribute]
        public string DataBlock;
        [XmlAttribute]
        public string SHA256;
        [XmlAttribute]
        public string SHA1;
        [XmlAttribute]
        public string MD5;
        [XmlAttribute]
        public string Name;
        [XmlElement("Match")]
        public LogReputationObject[] Matches;

        public LogLookupRequestResponse(
            LookupRequest lookupRequest,
            LookupResponse response)
        {
            if (lookupRequest == null)
            {
                throw new ArgumentNullException("lookupRequest");
            }

            this.Type = lookupRequest.Type;

            if (lookupRequest.SearchableFields != null)
            {
                foreach (Metadata metaData in lookupRequest.SearchableFields)
                {
                    if (metaData != null)
                    {
                        string metaDataValue;

                        if (metaData.Value.GetType().ToString() == "System.Byte[]")
                        {
                            string temp = BitConverter.ToString((byte[])metaData.Value);
                            metaDataValue = temp.Replace("-", string.Empty);
                        }
                        else
                        {
                            metaDataValue = metaData.Value.ToString();
                        }

                        switch (metaData.Name)
                        {
                            case "DataBlock":
                                this.DataBlock = metaDataValue;
                                break;

                            case "SHA256":
                                this.SHA256 = metaDataValue;
                                break;

                            case "SHA1":
                                this.SHA1 = metaDataValue;
                                break;

                            case "MD5":
                                this.MD5 = metaDataValue;
                                break;

                            case "Alias":
                            case "Display Name":
                                this.Name = metaDataValue;
                                break;
                        }
                    }
                }
            }

            if (response != null && response.Matches != null && response.Matches.Count > 0)
            {
                int i = 0;
                this.Matches = new LogReputationObject[response.Matches.Count];

                foreach (ReputationObject repuObj in response.Matches)
                {
                    if (repuObj != null)
                    {
                        this.Matches[i] = new LogReputationObject(repuObj);
                    }
                    else
                    {
                        TraceUtility.TraceError(Tracing.Source, "Logging - lookup response match {0} is null!", i);
                    }
                    i++;
                }
            }
        }

        private LogLookupRequestResponse()
        {
        }
    }

    public class LogListingResponse
    {
        [XmlAttribute("SeqNo")]
        public uint SequenceNumber;
        [XmlAttribute]
        public uint Status;
        [XmlAttribute]
        public string LatestEntryStamp;
        [XmlAttribute]
        public string ExpirationMins;
        [XmlElement]
        public LogReputationObject Match;
        [XmlArray]
        [XmlArrayItem("RepuObj")]
        public LogReputationObject[] Related;

        public LogListingResponse(ListingResponse response)
        {
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            this.SequenceNumber = response.SequenceNumber;
            this.Status = (uint)response.Status;

            if (response.ExpirationMins.HasValue)
            {
                this.ExpirationMins = XmlConvert.ToString(response.ExpirationMins.Value);
            }

            //
            // TODO: specify should we need to log response.Telemetry (it's not used at the moment)
            //

            if (response.LatestEntryStamp.HasValue)
            {
                this.LatestEntryStamp = XmlConvert.ToString(response.LatestEntryStamp.Value);
            }
            if (response.MatchedObject != null)
            {
                this.Match = new LogReputationObject(response.MatchedObject);
            }
            if (response.RelatedObjects != null)
            {
                this.Related = new LogReputationObject[response.RelatedObjects.Count];
                int i = 0;
                foreach (ReputationObject reputationObject in response.RelatedObjects)
                {
                    if (reputationObject != null)
                    {
                        this.Related[i] = new LogReputationObject(reputationObject);
                    }
                    else
                    {
                        TraceUtility.TraceError(Tracing.Source, "Logging - listing response, related {0} is null!", i);
                    }
                    i++;
                }
            }
        }

        private LogListingResponse()
        {
        }
    }

    public class LogReputationObject
    {
        [XmlAttribute]
        public Guid Guid;
        [XmlAttribute]
        public long Version;

        public LogReputationObject(ReputationObject repuObj)
        {
            if (repuObj == null)
            {
                throw new ArgumentNullException("repuObj");
            }

            this.Guid = repuObj.Guid;
            this.Version = repuObj.Version;
        }

        protected LogReputationObject()
        {
        }
    }

    public class LogMetadata
    {
        [XmlAttribute]
        public string Name;
        [XmlElement]
        public object Value;

        public LogMetadata(Metadata metaData)
        {
            if (metaData == null)
            {
                throw new ArgumentNullException("metaData");
            }

            this.Name = metaData.Name;
            this.Value = metaData.Value;
        }

        private LogMetadata()
        {
        }
    }

    public class LogCategoryReputation
    {
        [XmlAttribute]
        public uint CategoryId;
        [XmlAttribute]
        public byte Confidence;
        [XmlArray]
        [XmlArrayItem("Info")]
        public LogMetadata[] CategoryInfo;

        public LogCategoryReputation(CategoryReputation reputation)
        {
            if (reputation == null)
            {
                throw new ArgumentNullException("reputation");
            }

            this.CategoryId = reputation.CategoryId;
            this.Confidence = reputation.Confidence;

            if (reputation.CategoryInfo != null)
            {
                this.CategoryInfo = new LogMetadata[reputation.CategoryInfo.Count];
                int i = 0;
                foreach (Metadata categoryInformation in reputation.CategoryInfo)
                {
                    if (categoryInformation != null)
                    {
                        this.CategoryInfo[i] = new LogMetadata(categoryInformation);
                    }
                    i++;
                }
            }
        }

        private LogCategoryReputation()
        {
        }
    }

    public class LogClientToken
    {
        [XmlAttribute(AttributeName = "cid")]
        public Guid ClientId;
        [XmlAttribute]
        public Guid CustomerId;
        [XmlAttribute]
        public Guid DeploymentId;
        [XmlAttribute]
        public string CustomerVersion;

        public LogClientToken(ClientIdToken clientIdToken)
        {
            if (clientIdToken == null)
            {
                throw new ArgumentNullException("clientIdToken");
            }
            this.ClientId = clientIdToken.ClientId;
            this.CustomerId = clientIdToken.CustomerId;
            this.DeploymentId = clientIdToken.DeploymentId;
            this.CustomerVersion = clientIdToken.CustomerVersion;
        }

        private LogClientToken()
        {
        }
    }

    public class LookupLogEntry
    {
        [XmlAttribute]
        public DateTime timestamp = DateTime.UtcNow;
        [XmlAttribute]
        public uint DelayCommMins;
        [XmlAttribute]
        public uint OperationStatus;
        [XmlAttribute]
        public long OverrideStamp;
        [XmlAttribute]
        public string IP;
        [XmlElement]
        public LogClientToken ClientId;
        [XmlElement]
        public LogFilter Filter;
        [XmlArray("Lookups")]
        [XmlArrayItem("Lookup")]
        public LogLookupRequestResponse[] Lookups;

        private LookupLogEntry()
        {
        }

        public LookupLogEntry(
            ClientIdToken clientId,
            ICollection<LookupRequest> requests,
            Filter filter,
            StateToken stateTokenIn,
            ICollection<LookupResponse> responses,
            StateToken stateTokenOut,
            long latestOverrideStamp,
            uint delayCommMins,
            uint operationStatus,
            string clientIpAddress)
        {
            if (clientId != null)
            {
                this.ClientId = new LogClientToken(clientId);
            }
            else
            {
                TraceUtility.TraceWarning(Tracing.Source, "Null ClientIdToken passed to logger!");
            }

            if (filter != null)
            {
                this.Filter = new LogFilter(filter);
            }

            if (clientIpAddress != null)
            {
                this.IP = clientIpAddress;
            }

            this.DelayCommMins = delayCommMins;
            this.OperationStatus = operationStatus;
            this.OverrideStamp = latestOverrideStamp;

            if (requests != null)
            {
                int i = 0;
                this.Lookups = new LogLookupRequestResponse[requests.Count];

                foreach (LookupRequest lookupRequest in requests)
                {
                    if (lookupRequest != null)
                    {
                        LookupResponse lookupResponse;

                        if (responses != null && i < responses.Count)
                        {
                            lookupResponse = ((IList<LookupResponse>)responses)[i];
                        }
                        else
                        {
                            lookupResponse = null;
                            TraceUtility.TraceError(Tracing.Source, "Logging - Lookup requests and responses not match");
                        }

                        this.Lookups[i] = new LogLookupRequestResponse(lookupRequest, lookupResponse);
                    }

                    i++;
                }
            }
        }
    }

    public class LogListingToken
    {
        [XmlElement]
        public byte[] Data;

        public LogListingToken(ListingToken listingToken)
        {
            if (listingToken == null)
            {
                throw new ArgumentNullException("listingToken");
            }
            this.Data = listingToken.Data;
        }

        private LogListingToken()
        {
        }
    }

    public class LogStateToken
    {
        [XmlElement]
        public byte[] Data;

        public LogStateToken(StateToken stateToken)
        {
            if (stateToken == null)
            {
                throw new ArgumentNullException("stateToken");
            }
            this.Data = stateToken.Data;
        }

        private LogStateToken()
        {
        }
    }

    public class ListLogEntry
    {
        [XmlAttribute]
        public DateTime timestamp = DateTime.UtcNow;
        [XmlAttribute]
        public long LatestOverrideStamp;
        [XmlAttribute]
        public uint Remaining;
        [XmlAttribute]
        public uint DelayCommMins;
        [XmlAttribute]
        public uint OperationStatus;
        [XmlElement]
        public LogClientToken ClientId;
        [XmlElement]
        public LogFilter Filter;
        [XmlArray("Requests")]
        [XmlArrayItem("Request")]
        public LogListingRequest[] Requests;
        [XmlArray("Responses")]
        [XmlArrayItem("Response")]
        public LogListingResponse[] Responses;
        [XmlElement]
        public LogStateToken StateTokenIn;
        [XmlElement]
        public LogStateToken StateTokenOut;

        public ListLogEntry(
            ClientIdToken clientId,
            ICollection<ListingRequest> requests,
            Filter filter,
            ListingToken listingTokenIn,
            ListingToken listingTokenOut,
            StateToken stateTokenIn,
            StateToken stateTokenOut,
            ICollection<ListingResponse> responses,
            long latestOverrideStamp,
            uint remaining,
            uint delayCommMins,
            uint operationStatus)
        {
            if (clientId != null)
            {
                this.ClientId = new LogClientToken(clientId);
            }
            else
            {
                TraceUtility.TraceWarning(Tracing.Source, "Logging - null ClientIdToken!");
            }

            if (filter != null)
            {
                this.Filter = new LogFilter(filter);
            }
            if (stateTokenIn != null)
            {
                this.StateTokenIn = new LogStateToken(stateTokenIn);
            }
            if (stateTokenOut != null)
            {
                this.StateTokenOut = new LogStateToken(stateTokenOut);
            }
            this.LatestOverrideStamp = latestOverrideStamp;
            this.Remaining = remaining;
            this.DelayCommMins = delayCommMins;
            this.OperationStatus = operationStatus;

            if (requests != null)
            {
                this.Requests = new LogListingRequest[requests.Count];
                int i = 0;
                foreach (ListingRequest listingRequest in requests)
                {
                    if (listingRequest != null)
                    {
                        this.Requests[i] = new LogListingRequest(listingRequest);
                    }
                    i++;
                }
            }

            if (responses != null)
            {
                this.Responses = new LogListingResponse[responses.Count];
                int i = 0;
                foreach (ListingResponse listingResponse in responses)
                {
                    if (listingResponse != null)
                    {
                        this.Responses[i] = new LogListingResponse(listingResponse);
                    }
                    else
                    {
                        TraceUtility.TraceError(Tracing.Source, "Logging - listing response #{0} is null!", i);
                    }
                    i++;
                }
            }
        }

        private ListLogEntry()
        {
        }
    }

    public class GetOverridesLogEntry
    {
        [XmlAttribute]
        public DateTime timestamp = DateTime.UtcNow;
        [XmlElement]
        public LogClientToken ClientId;
        [XmlElement]
        public LogFilter Filter;
        [XmlElement]
        public long RequestOverrideStamp;
        [XmlElement]
        public long ResponseOverrideStamp;
        [XmlElement]
        public long LatestOverrideStamp;
        [XmlElement]
        public uint Remaining;
        [XmlElement]
        public LogStateToken StateTokenIn;
        [XmlElement]
        public LogStateToken StateTokenOut;
        [XmlAttribute]
        public uint DelayCommMins;
        [XmlAttribute]
        public uint OperationStatus;
        [XmlArray("Responses")]
        [XmlArrayItem("Response")]
        public LogReputationObject[] Responses;

        public GetOverridesLogEntry(
            ClientIdToken clientId,
            Filter filter,
            long requestOverrideStamp,
            StateToken stateTokenIn,
            ICollection<ReputationObject> responses,
            long responseClientOverrideStamp,
            StateToken stateTokenOut,
            long latestOverrideStamp,
            uint remaining,
            uint delayCommunicationMinutes,
            uint operationStatus)
        {
            if (clientId != null)
            {
                this.ClientId = new LogClientToken(clientId);
            }
            else
            {
                TraceUtility.TraceWarning(Tracing.Source, "Null ClientIdToken passed to logger!");
            }

            if (filter != null)
            {
                this.Filter = new LogFilter(filter);
            }

            if (responses != null)
            {
                this.Responses = new LogReputationObject[responses.Count];
                int i = 0;
                foreach (ReputationObject repuObj in responses)
                {
                    this.Responses[i++] = new LogReputationObject(repuObj);
                }
            }

            this.RequestOverrideStamp = requestOverrideStamp;
            this.ResponseOverrideStamp = responseClientOverrideStamp;
            this.LatestOverrideStamp = latestOverrideStamp;
            this.Remaining = remaining;
            if (stateTokenIn != null)
            {
                this.StateTokenIn = new LogStateToken(stateTokenIn);
            }
            if (stateTokenOut != null)
            {
                this.StateTokenOut = new LogStateToken(stateTokenOut);
            }
            this.DelayCommMins = delayCommunicationMinutes;
            this.OperationStatus = operationStatus;
        }

        private GetOverridesLogEntry()
        {
        }
    }

    public class LookupUrlLogEntry
    {
        [XmlAttribute]
        public DateTime timestamp = DateTime.UtcNow;
        [XmlAttribute]
        public uint OperationStatus;
        [XmlAttribute]
        public string Url;
        [XmlAttribute]
        public string IP;
        [XmlElement]
        public LogClientToken ClientId;
        [XmlArray("Categories")]
        [XmlArrayItem("Category")]
        public LogCategoryReputation[] Categories;

        private LookupUrlLogEntry()
        {
        }

        public LookupUrlLogEntry(
            ClientIdToken clientId,
            string url,
            ICollection<CategoryReputation> categories,
            uint operationStatus,
            string clientIpAddress)
        {
            if (clientId != null)
            {
                this.ClientId = new LogClientToken(clientId);
            }
            else
            {
                TraceUtility.TraceWarning(Tracing.Source, "Null ClientIdToken passed to logger!");
            }

            if (clientIpAddress != null)
            {
                this.IP = clientIpAddress;
            }

            this.OperationStatus = operationStatus;

            if (categories != null)
            {
                this.Categories = new LogCategoryReputation[categories.Count];

                int i = 0;
                foreach (CategoryReputation category in categories)
                {
                    this.Categories[i] = new LogCategoryReputation(category);

                    i++;
                }
            }
        }
    }


    public class WebServicesApiLogger : IWebServicesApiLogger
    {
        private DataPointsLogger dataPointsLogger = null;
        private Random randGenerator;

        private int m_logDenominator;
        private int m_logLookupObjectsOverallThreshold;
        private int m_logLookupMalwareThreshold;
        private int m_logListObjectsThreshold;
        private int m_logGetOverridesThreshold;
        private int m_logLookupUrlThreshold;
        
        private const int DefaultLogDenominator = 100;
        private const int DefaultOverallThresholdRatio = 1;
        private const int DefaultMalwareThresholdRatio = 1;
        private const int DataPointsLoggerEventBase = 240;
        private const int DataPointsLoggerAntiEventBase = 340;

        private int LogDenominator
        {
            get
            {
                return m_logDenominator;
            }
            set
            {
                if(value >= 0)
                {
                    m_logDenominator = value;
                }
                else
                {
                    m_logDenominator = DefaultLogDenominator;
                }
            }
        }

        private int LogLookupObjectsThreshold
        {
            get
            {
                return m_logLookupObjectsOverallThreshold;
            }
            set
            {
                if (value >= 0 && value <= LogDenominator)
                {
                    m_logLookupObjectsOverallThreshold = value;
                }
                else
                {
                    m_logLookupObjectsOverallThreshold = LogDenominator / DefaultOverallThresholdRatio;
                }
            }
        }

        private int LogLookupMalwareThreshold
        {
            get
            {
                return m_logLookupMalwareThreshold;
            }
            set
            {
                if (value >= 0 && value <= LogDenominator)
                {
                    m_logLookupMalwareThreshold = value;
                }
                else
                {
                    m_logLookupMalwareThreshold = LogDenominator / DefaultMalwareThresholdRatio;
                }
            }
        }

        private int LogListObjectsThreshold
        {
            get
            {
                return m_logListObjectsThreshold;
            }
            set
            {
                if (value >= 0 && value <= LogDenominator)
                {
                    m_logListObjectsThreshold = value;
                }
                else
                {
                    m_logListObjectsThreshold = LogDenominator / DefaultOverallThresholdRatio;
                }
            }
        }

        private int LogGetOverridesThreshold
        {
            get
            {
                return m_logGetOverridesThreshold;
            }
            set
            {
                if (value >= 0 && value <= LogDenominator)
                {
                    m_logGetOverridesThreshold = value;
                }
                else
                {
                    m_logGetOverridesThreshold = LogDenominator / DefaultOverallThresholdRatio;
                }
            }
        }

        private int LogLookupUrlThreshold
        {
            get
            {
                return m_logLookupUrlThreshold;
            }
            set
            {
                if (value >= 0 && value <= LogDenominator)
                {
                    m_logLookupUrlThreshold = value;
                }
                else
                {
                    m_logLookupUrlThreshold = LogDenominator / DefaultOverallThresholdRatio;
                }
            }
        }

        public WebServicesApiLogger()
        {
            try
            {                
                NameValueCollection loggerSettings = 
                    (NameValueCollection)ConfigurationManager.GetSection("WebServicesApiLogger/Settings");

                this.LogDenominator =
                    Int32.Parse(loggerSettings["LogDenominator"]);

                this.LogLookupObjectsThreshold =
                    Int32.Parse(loggerSettings["LookupObjectsThreshold"]);

                this.LogLookupMalwareThreshold =
                    Int32.Parse(loggerSettings["LookupMalwareThreshold"]);

                this.LogListObjectsThreshold =
                    Int32.Parse(loggerSettings["ListObjectsThreshold"]);

                this.LogGetOverridesThreshold =
                    Int32.Parse(loggerSettings["GetOverridesThreshold"]);

                this.LogLookupUrlThreshold =
                    Int32.Parse(loggerSettings["LookupUrlThreshold"]);
            }
            catch(Exception ex)
            {
                TraceUtility.TraceCatchException(Tracing.Source, ex);
                LogDenominator = -1;
                LogLookupObjectsThreshold = -1;
                LogLookupMalwareThreshold = -1;
                LogListObjectsThreshold = -1;
                LogGetOverridesThreshold = -1;
                LogLookupUrlThreshold = -1;
            }

            this.randGenerator = new Random(DateTime.Now.Millisecond);

            dataPointsLogger = DataPointsLogger.GetInstance;

            // Initializing Data Points Logger
            dataPointsLogger.Initialize(
                EventLogger.EventLog, 
                DataPointsLoggerEventBase, 
                DataPointsLoggerAntiEventBase,
                DeliveryServiceConfig.EventLoggerThrottleDisabled,
                string.Format("DeliveryService.V{0}.", Assembly.GetExecutingAssembly().GetName().Version.Major.ToString()));

            dataPointsLogger.StartLogging();
        }

        /// <summary>
        /// Flushes remaining in memory to the log file and drop the log file.  
        /// After this method is called no more calls to log API can take place.
        /// </summary>
        public void StopLogging()
        {
            // Stop and flush Data Points Logger
            dataPointsLogger.FlushLogFileAndStopLogging();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="o"></param>
        /// <returns></returns>
        private static string ToXml<T>(T o)
        {
            return XmlParser.ToXmlString<T>(o).Replace(
                " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"",
                string.Empty);
        }

        #region IWebServicesApiLogger Members

        public void LogLookupObjects(
            ClientIdToken clientId,
            ICollection<LookupRequest> requests,
            Filter filter,
            StateToken requestStateToken,
            ICollection<LookupResponse> response,
            StateToken responseStateToken,
            long latestOverrideStamp,
            uint delayCommMins,
            uint operationStatus,
            string clientIpAddress)
        {
            if (randGenerator.Next(LogDenominator) <= LogLookupObjectsThreshold)
            {
                LookupLogEntry logEntry = new LookupLogEntry(
                    clientId,
                    requests,
                    filter,
                    requestStateToken,
                    response,
                    responseStateToken,
                    latestOverrideStamp,
                    delayCommMins,
                    operationStatus,
                    clientIpAddress);

                DataPoint logData = new DataPoint();
                logData.Add("XmlRequestResponse", ToXml(logEntry));
                this.dataPointsLogger.Enqueue(logData);
            }
        }

        public void LogListRelatedObjects(
            ClientIdToken clientId,
            ICollection<ListingRequest> requests,
            Filter filter,
            StateToken requestStateToken,
            ListingToken requestListingToken,
            ICollection<ListingResponse> responses,
            StateToken responseStateToken,
            ListingToken responseListingToken,
            long latestOverrideStamp,
            uint remaining,
            uint delayCommunicationMinutes,
            uint operationStatus)
        {
            if (randGenerator.Next(LogDenominator) <= LogListObjectsThreshold)
            {
                ListLogEntry logEntry = new ListLogEntry(
                    clientId,
                    requests,
                    filter,
                    requestListingToken,
                    responseListingToken,
                    requestStateToken,
                    responseStateToken,
                    responses,
                    latestOverrideStamp,
                    remaining,
                    delayCommunicationMinutes,
                    operationStatus);

                DataPoint logData = new DataPoint();
                logData.Add("XmlRequestResponse", ToXml(logEntry));
                this.dataPointsLogger.Enqueue(logData);
            }
        }

        public void LogGetOverrides(
            ClientIdToken clientId,
            Filter filter,
            long requestOverrideStamp,
            StateToken requestStateToken,
            ICollection<ReputationObject> responses,
            long responseClientOverrideStamp,
            StateToken responseStateToken,
            long latestOverrideStamp,
            uint remaining,
            uint delayCommunicationMinutes,
            uint operationStatus)
        {
            if (randGenerator.Next(LogDenominator) <= LogGetOverridesThreshold)
            {
                GetOverridesLogEntry logEntry = new GetOverridesLogEntry(
                    clientId,
                    filter,
                    requestOverrideStamp,
                    requestStateToken,
                    responses,
                    responseClientOverrideStamp,
                    responseStateToken,
                    latestOverrideStamp,
                    remaining,
                    delayCommunicationMinutes,
                    operationStatus);

                DataPoint logData = new DataPoint();
                logData.Add("XmlRequestResponse", ToXml(logEntry));
                this.dataPointsLogger.Enqueue(logData);
            }
        }


        public void LogLookupCategoriesForUrl(
            ClientIdToken clientId,
            string url,
            List<CategoryReputation> categories,
            uint operationStatus,
            string clientIpAddress)
        {
            if (randGenerator.Next(LogDenominator) <= LogLookupUrlThreshold)
            {
                LookupUrlLogEntry logEntry = new LookupUrlLogEntry(
                    clientId,
                    url,
                    categories,
                    operationStatus,
                    clientIpAddress);

                DataPoint logData = new DataPoint();
                logData.Add("XmlRequestResponse", ToXml(logEntry));
                this.dataPointsLogger.Enqueue(logData);
            }

        }

        #endregion
    }
}